import type { TreeDataNode, TreeProps } from 'antd';
import { Form, Modal, Tree } from 'antd';
import { useImperativeHandle, useState } from 'react';

import menusApi from '@/api/menusApi';
import rolesApi from '@/api/rolesApi';
import { message } from '@/components/AntdGlobal';
import { IMenu, type IRole } from '@/types/api';
import type { IAction, IModalProp } from '@/types/modal';

const SetPermission = (props: IModalProp<IRole.RoleItem>) => {
    /* 数据管理 ---------------------------------------------------*/
    const [visible, setVisible] = useState(false);
    const [action, setAction] = useState<IAction>('create');
    const [menuList, setMenuList] = useState<IMenu.MenuItem[]>([]);
    const [checkedKeys, setCheckedKeys] = useState<string[]>([]);
    const [expandedKeys, setExpandedKeys] = useState<string[]>([]);
    const [roleInfo, setRoleInfo] = useState<IRole.RoleItem>();
    const [permission, setPermission] = useState<IRole.Permission>();

    //* 逻辑代码 ---------------------------------------------------*/
    /**
     * 暴露子组件open方法，供父组件中调用props.mRef?.openModal()方法
     */
    useImperativeHandle(props.mRef, () => {
        return {
            openModal
        };
    });

    /**弹框显示
     * @param action 类型
     * @param data 数据
     */
    const openModal = async (action: IAction, data?: IRole.RoleItem) => {
        setVisible(true);
        setAction(action);
        setRoleInfo(data);
        // 数据时效性，每次打开弹窗时重新获取数据
        await getMenusList();
        if (action === 'setting' && data) {
            setCheckedKeys(data?.permissionList?.checkedKeys || []);
        }
    };

    /**
     * 递归获取所有 menuId
     * @param list
     * @returns
     */
    const getAllMenuIds = (list: IMenu.MenuItem[]): string[] => {
        let ids: string[] = [];
        list.forEach((item) => {
            ids.push(item.menuId);
            if (item.children) {
                ids = ids.concat(getAllMenuIds(item.children));
            }
        });
        return ids;
    };

    /**获取菜单列表
     */
    const getMenusList = async () => {
        const { data } = await menusApi.getMenusList();
        setMenuList(data);
        // defaultExpandAll 只在 Tree 首次渲染时生效，异步加载 menuList 后不会自动全部展开。
        // 这里设置全部展开
        setExpandedKeys(getAllMenuIds(data));
    };

    /**菜单选中
     * @param checkedKeysValue
     * @param info
     */
    const onCheck: TreeProps['onCheck'] = (checkedKeysValue, info) => {
        // 受控组件同步UI选中状态
        setCheckedKeys(checkedKeysValue as string[]);

        // 组装请求数据，checkedKeys只保留末级菜单ID,halfCheckedKeys保留tree上游所有半选中
        const checkedKeys: string[] = [];
        const parentKeys: string[] = [];
        // info.checkedNodes 是全选中节点的完整数据
        (info.checkedNodes as unknown as IMenu.MenuItem[]).map((node) => {
            if (node.menuType === IMenu.EMenuType.BUTTON) {
                // 只需要末级,按钮级别的menuId
                checkedKeys.push(node.menuId);
            } else {
                // 从选中的菜单中剔除，稍后加入到半全选中,避免后续添加末级菜单时由于父级菜单选中状态，子级自动全部选中，导致新增末级菜单被选中
                parentKeys.push(node.menuId);
            }
        });

        setPermission({
            roleId: roleInfo?.roleId || '',
            permissionList: {
                checkedKeys,
                // halfCheckedKeys:菜单级别，后端作为侧边栏菜单的权限依据,和antd Tree 的半选中含义不同
                halfCheckedKeys: parentKeys.concat(info.halfCheckedKeys as string[])
            }
        });
    };

    /**表单提交
     */
    const handleSubmit = async () => {
        if (action === 'setting' && permission) {
            await rolesApi.updatePermission(permission);
            message.success('权限设置成功');
            // 关闭弹窗，重置表单数据
            handleCancel();
            // 父组件更新列表
            props.update();
        }
    };

    /**取消操作
     */
    const handleCancel = () => {
        setVisible(false);
        setCheckedKeys([]);
        setPermission(undefined);
    };

    return (
        <Modal
            title="设置权限"
            width={800}
            open={visible}
            okText="确定"
            cancelText="取消"
            onOk={handleSubmit}
            onCancel={handleCancel}
        >
            <Form>
                <Form.Item label="角色名称">{roleInfo?.roleName}</Form.Item>
                <Form.Item label="权限列表">
                    <Tree
                        checkable
                        expandedKeys={expandedKeys}
                        defaultExpandAll
                        onCheck={onCheck}
                        checkedKeys={checkedKeys}
                        treeData={menuList as unknown as TreeDataNode[]}
                        fieldNames={{
                            title: 'menuName',
                            key: 'menuId',
                            children: 'children'
                        }}
                    />
                </Form.Item>
            </Form>
        </Modal>
    );
};

export default SetPermission;
